package matchthreegame.gameLogic;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.HashSet;

import com.smartfoxserver.v2.entities.data.SFSArray;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.smartfoxserver.v2.extensions.SFSExtension;

public class Player {
	
	public static final String SHOULD_USE_HERO  		   = "SUH";
	public static final String HERO_TYPE    		       = "HT";
	public static final String HERO_CONDITIONS             = "HC";
	public static final String HERO_SKILLS_ON_MYSELF       = "HSM";
	public static final String HERO_SKILLS_ON_OTHER_PLAYER = "HSOP";
	public static final String PLAYER_ID      		       = "PID";
	
	public static final int COOKIE_TYPE_1 = 1;
	public static final int COOKIE_TYPE_2 = 2;
	public static final int COOKIE_TYPE_3 = 3;
	public static final int COOKIE_TYPE_4 = 4;
	public static final int COOKIE_TYPE_5 = 5;
	public static final int COOKIE_TYPE_6 = 6;
	
	private static final int MATCHED_4_COOKIES_MULTIPLIER = 1;
	private static final int MATCHED_5_COOKIES_MULTIPLIER = 3;
	
	public long id;
	public int playerID;
	public String name;
	public int cookieType1Counter;
	public int cookieType2Counter;
	public int cookieType3Counter;
	public int cookieType4Counter;
	public int cookieType5Counter;
	public int cookieType6Counter;
	private int matched4CookiesCounter;
	private int matched5CookiesCounter;
	public HashMap<Integer, Integer> gameWinConditions;
	public Hero hero;
	private WeakReference<SFSExtension> roomExtension;
	
	public Player(SFSExtension roomExtension) 
	{
		
		this.roomExtension = new WeakReference<SFSExtension>(roomExtension);
		this.playerID = 0;
		this.cookieType1Counter = 0;
		this.cookieType2Counter = 0;
		this.cookieType3Counter = 0;
		this.cookieType4Counter = 0;
		this.cookieType5Counter = 0;
		this.cookieType6Counter = 0;
		this.matched4CookiesCounter = 0;
		this.matched5CookiesCounter = 0;
		
	}
	
	
	public void initHero(int heroType,int heroProduces, int heroAttack) {
		
		this.hero = new Hero(heroType, heroProduces, heroAttack);
		
	}
	
	
//	public void initHeroWithType(int heroType) {
//		
//		this.hero = new Hero(heroType);
//		
//	}
	
	
	/*
	 * Updates counter values for cookies from given chains
	 */
	public void calculateScoreForChains(HashSet<GameChain> chains, Player myself, Player otherPlayer) {
		
		for (GameChain chain : chains) {
			
			calculateScoreForChain(chain);
			hero.calculateScoreForChain(chain, myself, otherPlayer);
			
			if ( chain.cookies.size() == 4 ) {
				
				this.matched4CookiesCounter += 1;
				
			} else if ( chain.cookies.size() == 5 ) {
				
				this.matched5CookiesCounter += 1;
				
			}
			
		}
		
		addComboCookies(myself, otherPlayer);
		
		normalizeCountersForConditiones();
		
	}
	
	
	private void addComboCookies(Player myself, Player otherPlayer) {
		
		int matched4ComboCookies = matched4CookiesCounter * MATCHED_4_COOKIES_MULTIPLIER;
		int matched5ComboCookies = matched5CookiesCounter * MATCHED_5_COOKIES_MULTIPLIER;
		
		// reset matched combo counters
		this.matched4CookiesCounter = 0;
		this.matched5CookiesCounter = 0;
		
		int comboCookiesToBeAdded = matched4ComboCookies + matched5ComboCookies;
		
//		roomExtension.get().trace("Player comboCookiesToBeAdded: " + comboCookiesToBeAdded);
		
		//update counters
		this.cookieType1Counter += comboCookiesToBeAdded;
		this.cookieType2Counter += comboCookiesToBeAdded;
		this.cookieType3Counter += comboCookiesToBeAdded;
		this.cookieType4Counter += comboCookiesToBeAdded;
		this.cookieType5Counter += comboCookiesToBeAdded;
		this.cookieType6Counter += comboCookiesToBeAdded;
		
		hero.addComboCookies(comboCookiesToBeAdded, myself, otherPlayer);
		
	}
	
	
	public void useHeroSkill(HashMap<Integer, Integer> heroSkill) {
		
		//update Player counters
		this.cookieType1Counter += heroSkill.get(1);
		this.cookieType2Counter += heroSkill.get(2);
		this.cookieType3Counter += heroSkill.get(3);
		this.cookieType4Counter += heroSkill.get(4);
		this.cookieType5Counter += heroSkill.get(5);
		this.cookieType6Counter += heroSkill.get(6);
		
		correctNegativeCounters();
		
		// update Hero counters
		hero.cookieType1Counter += heroSkill.get(1);
		hero.cookieType2Counter += heroSkill.get(2);
		hero.cookieType3Counter += heroSkill.get(3);
		hero.cookieType4Counter += heroSkill.get(4);
		hero.cookieType5Counter += heroSkill.get(5);
		hero.cookieType6Counter += heroSkill.get(6);
		
		hero.correctNegativeCounters();
		
	}
	
	
	// makes all Negative values to be 0
	private void correctNegativeCounters() {
		
		cookieType1Counter = cookieType1Counter < 0 ? 0 : cookieType1Counter;
		cookieType2Counter = cookieType2Counter < 0 ? 0 : cookieType2Counter;
		cookieType3Counter = cookieType3Counter < 0 ? 0 : cookieType3Counter;
		cookieType4Counter = cookieType4Counter < 0 ? 0 : cookieType4Counter;
		cookieType5Counter = cookieType5Counter < 0 ? 0 : cookieType5Counter;
		cookieType6Counter = cookieType6Counter < 0 ? 0 : cookieType6Counter;
		
	}
	
	
	// Calculate score for particular Chain
	private void calculateScoreForChain(GameChain chain) {
	
		int value = 1;
		
		for (GameCookie cookie : chain.cookies) {
			
			switch (cookie.cookieType) {
			case 1:
                cookieType1Counter += value;
                break;
            case 2:
                cookieType2Counter += value;
                break;
            case 3:
                cookieType3Counter += value;
                break;
            case 4:
                cookieType4Counter += value;
                break;
            case 5:
                cookieType5Counter += value;
                break;
            case 6:
                cookieType6Counter += value;
                break;
                
            default:
                break;
			}
			
		}
		
	}
	
	
	// If one of the counters is more than the conditiones will be set to his target value 
	private void normalizeCountersForConditiones() {
		
		Integer cookieType1Target = gameWinConditions.get(1);
		Integer cookieType2Target = gameWinConditions.get(2);
		Integer cookieType3Target = gameWinConditions.get(3);
		Integer cookieType4Target = gameWinConditions.get(4);
		
		if ( cookieType1Counter > cookieType1Target ) {
			cookieType1Counter = cookieType1Target;
		}
		
		if ( cookieType2Counter > cookieType2Target ) {
			cookieType2Counter = cookieType2Target;
		}
		
		if ( cookieType3Counter > cookieType3Target ) {
			cookieType3Counter = cookieType3Target;
		}
		
		if ( cookieType4Counter > cookieType4Target ) {
			cookieType4Counter = cookieType4Target;
		}
		
	}
	
	
	/*
	 * Reset all counters to 0
	 */
	public void resetCounters()
	{
		
		this.cookieType1Counter = 0;
		this.cookieType2Counter = 0;
		this.cookieType3Counter = 0;
		this.cookieType4Counter = 0;
		this.cookieType5Counter = 0;
		this.cookieType6Counter = 0;
		
		// Reset Hero counters
		hero.resetCounters();
		
	}

	
	/*
	 * Returns PlayersInfo as SFSArray
	 */
	public SFSArray playerInfoAsSFSArray()
	{
		// at index 0 is playerID
	    // at indexes from 1 to 6 are values for the cookies counters
		SFSArray cookiesScoreSfsArray = new SFSArray();
		cookiesScoreSfsArray.addInt(this.playerID);
		cookiesScoreSfsArray.addInt(this.cookieType1Counter);
		cookiesScoreSfsArray.addInt(this.cookieType2Counter);
		cookiesScoreSfsArray.addInt(this.cookieType3Counter);
		cookiesScoreSfsArray.addInt(this.cookieType4Counter);
		cookiesScoreSfsArray.addInt(this.cookieType5Counter);
		cookiesScoreSfsArray.addInt(this.cookieType6Counter);
		
		return cookiesScoreSfsArray;
	}
	
	public boolean didWin()
	{
		
		Integer cookieType1Target = gameWinConditions.get(1);
		Integer cookieType2Target = gameWinConditions.get(2);
		Integer cookieType3Target = gameWinConditions.get(3);
		Integer cookieType4Target = gameWinConditions.get(4);
		Integer cookieType5Target = gameWinConditions.get(5);
		Integer cookieType6Target = gameWinConditions.get(6);
		
		// Return False if some of the counters is less than the target value
		if ( cookieType1Counter < cookieType1Target ) {
			return false;
		} else if ( cookieType2Counter < cookieType2Target ) {
			return false;
		} else if ( cookieType3Counter < cookieType3Target ) {
			return false;
		} else if ( cookieType4Counter < cookieType4Target ) {
			return false;
		} else if ( cookieType5Counter < cookieType5Target ) {
			return false;
		} else if ( cookieType6Counter < cookieType6Target ) {
			return false;
		}
		
		return true;
	}
	
	
	public SFSObject getHeroWaveInfoAsSFSObject() {
		
		boolean shoudUseHero = hero.wasHeroUsedThisWave();
		int heroType = hero.type;
		
		SFSObject sfsHeroInfo = new SFSObject();
		sfsHeroInfo.putBool(SHOULD_USE_HERO, shoudUseHero);
		sfsHeroInfo.putInt(HERO_TYPE, heroType);
		
		hero.setWasHeroUsedThisWave(false);
		
		return sfsHeroInfo;
		
	}
	
	
	public SFSArray getHeroCountersInfoAsSFSArray() {
		
		return hero.heroCountersAsSFSArray();
		
	}
	
	
	public SFSObject getHeroUsageConditions() {
		
		SFSObject heroUsageConditions = SFSObject.newInstance();
		heroUsageConditions.putInt(PLAYER_ID, playerID);
		
		SFSArray sfsHeroUsageConditions = this.hero.getUsageConditionsAsSFSArray();
		heroUsageConditions.putSFSArray(HERO_CONDITIONS, sfsHeroUsageConditions);
		
		return heroUsageConditions;
		
	}
	
	
	public SFSObject getHeroSkillsOnMyself() {
		
		SFSObject heroSkillsOnMyself = SFSObject.newInstance();
		heroSkillsOnMyself.putInt(PLAYER_ID, playerID);
		
		SFSArray sfsHeroSkillsOnMyself = this.hero.getSkillsOnMyselfAsSFSArray();
		heroSkillsOnMyself.putSFSArray(HERO_SKILLS_ON_MYSELF, sfsHeroSkillsOnMyself);
		
		return heroSkillsOnMyself;
		
	}
	
	
	public SFSObject getHeroSkillsOnOtherPlayer() {
		
		SFSObject heroSkillsOnOtherPlayer = SFSObject.newInstance();
		heroSkillsOnOtherPlayer.putInt(PLAYER_ID, playerID);
		
		SFSArray sfsHeroSkillsOnOtherPlayer = this.hero.getSkillsOnOtherPlayerAsSFSArray();
		heroSkillsOnOtherPlayer.putSFSArray(HERO_SKILLS_ON_OTHER_PLAYER, sfsHeroSkillsOnOtherPlayer);
		
		return heroSkillsOnOtherPlayer;
		
	}
	
	
	public HashMap<Integer, Integer> getNeededCookies(HashMap<Integer, Integer> winConditions) {
		
		HashMap<Integer, Integer> neededCookies = new HashMap<Integer, Integer>();
		
		int neededType1 = winConditions.get(COOKIE_TYPE_1) - this.cookieType1Counter;
		int neededType2 = winConditions.get(COOKIE_TYPE_2) - this.cookieType2Counter;
		int neededType3 = winConditions.get(COOKIE_TYPE_3) - this.cookieType3Counter;
		int neededType4 = winConditions.get(COOKIE_TYPE_4) - this.cookieType4Counter;
		int neededType5 = winConditions.get(COOKIE_TYPE_5) - this.cookieType5Counter;
		int neededType6 = winConditions.get(COOKIE_TYPE_6) - this.cookieType6Counter;
		
		neededCookies.put(COOKIE_TYPE_1, neededType1);
		neededCookies.put(COOKIE_TYPE_2, neededType2);
		neededCookies.put(COOKIE_TYPE_3, neededType3);
		neededCookies.put(COOKIE_TYPE_4, neededType4);
		neededCookies.put(COOKIE_TYPE_5, neededType5);
		neededCookies.put(COOKIE_TYPE_6, neededType6);
		
		return neededCookies;
		
	}
	
	
}
